# -*- coding: utf-8 -*-
# @file    : views
# @Date    : 2020/11/19
# @Author  :
# @Version : 1.0.0
import os
import json
import requests

from flask import Blueprint, request, make_response, redirect
from werkzeug.exceptions import HTTPException, NotFound

from .log import logger as _logger
from ._misc import load_file, proxy, headers2dict, get_abs_path, store_file, report_process_time
from .constant import POE_HOST, POE_REMOTE, ROOT_PATH, CDN_REMOTE, POE_INDEX, DEFAULT_UA
from .config import config
from .res_patch import index_html_patch, icon_host_patch, trade_js_patch

user_config = config['user']
bp = Blueprint('app', __name__,
               static_folder=user_config['static_dir'],
               static_url_path="",
               root_path=ROOT_PATH)


class RemoteError(HTTPException):
    code = 200
    description = (
        "腾讯服务器未返回正确的响应."
    )


@bp.route('/')
@bp.route('/trade/<path:sub_path>')
@report_process_time
def index(sub_path=None):
    """
    市集主页
    :return:
    """
    abs_path = get_abs_path(os.path.join(bp.static_folder, 'index.html'))
    if os.path.exists(abs_path):
        return bp.send_static_file('index.html')
    req_headers = {
        'User-Agent': DEFAULT_UA
    }
    _logger.info("主页缓存不存在, 尝试从远程拉取...")
    remote_resp = proxy(requests.get, url=POE_INDEX, headers=req_headers)
    if remote_resp and remote_resp.status_code == 200 and remote_resp.content:
        file = index_html_patch(remote_resp.content)
        _logger.info("存储主页缓存->%s", abs_path)
        store_file(abs_path, file)
        return bp.send_static_file('index.html')

    return NotFound("请求的页面找不到了, 请刷新几次重试:\n\n"
                    "1. 找不到主页的缓存数据.\n"
                    "2. 从远程主机拉取数据失败.")


@bp.route('/api/<path:sub_path>', methods=['POST', 'GET'])
@report_process_time
def api_proxy(sub_path, **kwargs):
    """
    API 代理
    :param sub_path:
    :param kwargs:
    :return:
    """
    store_flag = False

    if request.path in user_config['api_cache_list'] or []:
        whole_path = request.path[1:]
        abs_path = get_abs_path(os.path.join(bp.static_folder, whole_path))
        if os.path.exists(abs_path):
            return json.loads(load_file(abs_path))
        _logger.info("API缓存不存在, 尝试从远程拉取 : %s", request.path)
        store_flag = True

    # 模拟请求
    remote_addr = POE_REMOTE + request.environ['REQUEST_URI']
    _logger.info("代理请求: %s", remote_addr)
    # 复制请求头
    req_headers = dict(request.headers)
    req_headers['Host'] = POE_HOST
    req_headers['Origin'] = POE_REMOTE
    req_headers['Referer'] = remote_addr
    # 移除 Content-Length
    'Content-Length' in req_headers and req_headers.pop('Content-Length')

    if request.method == 'POST':
        request_kw = {
            'url': remote_addr,
            'headers': req_headers,
            'data': request.data,
            'timeout': user_config['proxy_time_out']
        }
        remote_resp = proxy(requests.post, **request_kw)
        if not remote_resp:
            _logger.info("腾讯服务器未正确响应")
            return RemoteError()

    else:  # GET
        request_kw = {
            'url': remote_addr,
            'headers': req_headers,
            'timeout': user_config['proxy_time_out']
        }
        remote_resp = proxy(requests.get, **request_kw)
        if not remote_resp:
            _logger.info("腾讯服务器未正确响应")
            return RemoteError()

    resp_content = remote_resp.content
    if sub_path.startswith('trade/fetch/'):
        resp_content = icon_host_patch(resp_content, request.host)

    if store_flag:
        _logger.info("存储API数据缓存: %s", request.path)
        store_file(abs_path, remote_resp.content)

    resp_status_code = remote_resp.status_code
    resp_headers = headers2dict(remote_resp.headers)
    response = make_response(resp_content, resp_status_code)
    # 复制响应头
    response.headers.update(resp_headers)

    return response


@bp.route('/image/<path:sub_path>')
@bp.route('/gen/image/<path:sub_path>')
@bp.route('/font/<path:sub_path>')
@bp.route('/css/<path:sub_path>')
@bp.route('/js/<path:sub_path>')
@report_process_time
def static_proxy(sub_path):
    """
    静态资源代理
    支持自动缓存
    :param sub_path:
    :return:
    """
    whole_path = request.path[1:]
    abs_path = get_abs_path(os.path.join(bp.static_folder, whole_path))
    if os.path.exists(abs_path):
        return bp.send_static_file(whole_path)
    _logger.info("未找到本地资源: %s", whole_path)
    remote_addr = CDN_REMOTE + request.full_path
    response = proxy(requests.get, url=remote_addr, timeout=user_config['proxy_time_out'])
    if response and response.status_code == 200:
        _logger.info("存储远程资源->%s", abs_path)
        resp_content = response.content

        flag = True

        if request.path.startswith('/js/trade'):
            resp_content = trade_js_patch(resp_content)
        try:
            store_file(abs_path, resp_content)
        except FileExistsError as e:
            _logger.error(e)
        except Exception as e:
            _logger.error(e)
            flag = False

        if flag:
            return bp.send_static_file(whole_path)

    # 处理失败的重定向到到原来资源的地址
    return redirect(remote_addr)
